package com.one.blocks.eds.core;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import com.zaxxer.hikari.HikariPoolMXBean;
import lombok.Data;

import javax.sql.DataSource;
import java.util.Properties;

/**
 * @author <a href="mailto:idler41@163.con">linfuxin</a> created on 2023-09-11 09:59:13
 */
@Data
public class ExpireDataSourceHolder {
    /**
     * 每个数据源维护独立的ClassLoader，增强隔离性
     */
    private ClassLoader classLoader;

    private String dsKey;

    /**
     * 物理数据源
     */
    private final DataSource dataSource;
    /**
     * 访问时间，即使不使用 volatile，在大多数情况下也不会有严重问题
     * 1. JVM 会在某些同步点刷新缓存
     * 2. 时间稍微滞后是可以接受的（几毫秒的差异不影响过期判断）
     */
    private long accessTime;

    private volatile boolean removed = false;

    public ExpireDataSourceHolder(String dsKey, Properties properties) {
        this(dsKey, new HikariDataSource(new HikariConfig(properties)));
    }

    public ExpireDataSourceHolder(String dsKey, DataSource dataSource) {
        this.dsKey = dsKey;
        this.dataSource = dataSource;
    }

    /**
     * 数据源未使用，且处于空闲状态超过10分钟即可真正关闭(主要解决ExpireDataSource无锁get后马上被标记为删除的并发问题，通过较长时间的空闲时间可以一定的规避该问题)
     *
     * @return 是否可以关闭
     */
    public boolean isCanClose() {
        //noinspection AlibabaLowerCamelCaseVariableNaming
        HikariPoolMXBean poolMXBean = ((HikariDataSource) dataSource).getHikariPoolMXBean();
        return poolMXBean.getActiveConnections() == 0 && poolMXBean.getThreadsAwaitingConnection() == 0;
    }

    public void close() {
        ((HikariDataSource) dataSource).close();
    }
}
